<script>
      /*
              四、通用调用指南


                        1、注意事项：

                                ①、凭证安全

                                          ClientSecret 严禁暴露在前端代码中，必须在后端服务器处理

                                          建议将 access-token 存储在Redis或数据库中，并设置过期时间

                                ②、调用频率限制

                                          应用级 access_token 
                                          
                                          部分API有单独的频率限制，需参考官方文档。

         
                        2、申请权限

                                    在调用任何 OpenAPI 前，必须先申请并获得对应的接口权限。

                                    抖音开放平台通过权限管理确保数据安全和合规使用，不同类型的API（如用户信息、交易、内容分享等）需单独申请。

                                    ★、注意：

                                            ①、登录开放平台：  访问 “抖音开放平台控制台” ，选择目标小程序也应用。

                                            ②、选择能力权限：  在应用详情页左侧导航栏进入【能力管理】，根据API类型（如【用户信息--获取手机号】）找到对应的权限项。

                                            ③、提交申请材料：  点击【申请开通】，填写清晰的使用场景说明 （例如：“用户在小程序内下单时需校验收货地址，需申请收货地址权限”）、

                                                              上传场景示意图（如交互流程图），确包符合《抖音开放平台开发者协议》

                                            ④、等待审核：      审核通常在1-3个工作日内完成，通过后权限状态显示为【已开通】


                        3、步骤一：获取用户临时登录凭证 （code）

                                        ①、在小程序前端代码中，调用 tt.login 获取用户临时登录凭证 code。

                                                  tt.login({
                                                    success:(res)=>{
                                                        if(res.code){
                                                           // 将code发送到后端服务器
                                                           tt.request({
                                                              url:'https://your-server.com/api/auth',
                                                              method:'Post',
                                                              data:{code:res.code},
                                                              success:(res)=>{
                                                                  console.log('登录成功，获取到用户身份',res.data);
                                                              },
                                                              fail:(err)=>{
                                                                  console.error('登录失败'，err);
                                                              }
                                                           });
                                                        }else{
                                                            console.error('获取 code 失败'，res.errMsg);
                                                        }
                                                    },
                                                    fail:(err)=>{
                                                       console.error('调用 tt.login 失败：'，err)
                                                    }
                                                  })


                                       ②、（可选） 若需获取用户敏感信息（如手机号、昵称），需先引导用户授权。

                                                 // 示例：  获取用户信息授权

                                                 tt.getUserInfo({
                                                    success:(res)=>{
                                                       console.log('用户信息：',res.userInfo)
                                                    },
                                                    fail:(err)=>{
                                                        console.error('用户拒绝授权',err)
                                                    }
                                                 })


                      5、步骤二： 获取 open_id 和 acces_token 

                                    后端接收前端传来的 code， 调用抖音开放平台接口 code2Session 换取 open_id 和  access_token:
                                              import com.aliyun.tea.TeaException;
                                              import com.douyin.openapi.client.Client;
                                              import com.douyin.openapi.client.models.*;
                                              import com.douyin.openapi.credential.models.Config;   credential:证件；资格证明（最常用）

                                              public class Main{
                                                  try{
                                                        Config config = new Config().setClientKey('tt******').setClientSecret('cbs****');  // 改成自己的app_id 跟 secret
                                                        Client  client = new Client(config);

                                                        /--
                                                            构建请求参数，该代码示例只给出部分参数，请用户根据需要自行构建参数值

                                                                token: 
                                                                    1、若用户自行维护 token,将用户维护的token赋值给该参数即可

                                                                    2、SKD包中有获取token的函数，请根据接口 path 在《OpenAPI SDK 总览》文档中查找获取 token 函数的名字。

                                                                            在使用过程中，请注意 token互刷问题

                                                                header:

                                                                      SDK 中默认填充  content-type 请求头，若不需要填充除 content-type之外的请求头，删除该参数即可
                                                        --/

                                                        V2Jscode2sessionRequest sdkRequest = new V2Jscode2sessionRequest();
                                                        sdkRequest.setAnonymousCode("EpFjYuap01");
                                                        sdkRequest.setAppid("tt4233**");
                                                        skdRequest.setCode("YAH9JFcEc4");
                                                        sdkRequest.setSecret("83Soi1UKQ6");
                                                        V2Jscode2sessionResponse sdkResponse = client.V2JsCode = client.V2Jscode2session(sdkRequest);
                                                  }
                                                  catch(TeaException e){
                                                        Systen.out.printIn(e.getMEssage());
                                                  }
                                                  catch(Exception e){
                                                        System.out.printIn(e.getMessage());                                           
                                                  }
                                              }

                                        ★、区分两种 access_token 类型

                                                      ①、用户级access_token :  通过 code2Session接口获取，与特定用户关联，用于调用用户相关API (如获取用户信息)。

                                                      ②、应用级access_token:  通过 client_credential 接口获取，全局唯一，用于调用无用户身份的API （如获取小程序配置）。

                                                      // 获取应用级 access_token

                                                          def get_app_access_token();

                                                                  url =  f"https://developer.toutiao.com/api/apps/token"

                                                                  params ={
                                                                      "appid":CLIENT_KEY,
                                                                      "secret"：CLIENT_SECRET,
                                                                      "grant_type":"client_credential"
                                                                  }

                                                                  reponse = requests.get(url,params=params)
                                                                  result = response.json();

                                                                  if "access_token" in result:
                                                                      return result["access_token"]
                                                                  else:
                                                                      raise Exception(f"获取应用级 access_token 失败：{result}");


                      6、步骤三：使用access_token 调用  OpenAPI

                                  <1>、用户级API调用示例 （获取用户信息）

                                            import java.io.BufferedReader;
                                            import java.io.IOException;
                                            import java.io.InputStreamReader;
                                            import java.net.HttpURLConnection;
                                            import java.net.URL;
                                            import java.net.URLEncoder;
                                            import java.nio.charset.StandardCharsets;
                                            import com.alibaba.fastjson.JSONObject;

                                            public class DouyinUserApi {
                                                // 替换为你的应用凭证
                                                    private static final String APP_ID = "your_app_id";
                                                    private static final String APP_SECRET = "your_app_secret";
                                                
                                                // API 接口地址
                                                    private static final String TOKEN_URL = "https://developer.toutiao.com/api/apps/jscode2session";
                                                    private static final String REFRESH_TOKEN_URL = "https://developer.toutiao.com/api/apps/refresh_token";
                                                    private static final String USER_INFO_URL = "https://developer.toutiao.com/api/user/info";

                                                /--
                                                * 使用 code 获取 session 信息（含 access_token 和 open_id）
                                                --/
                                                    public static JSONObject getSessionByCode(String code) {
                                                        try {
                                                            String url = TOKEN_URL + "?" +
                                                                    "appid=" + URLEncoder.encode(APP_ID, StandardCharsets.UTF_8) +
                                                                    "&secret=" + URLEncoder.encode(APP_SECRET, StandardCharsets.UTF_8) +
                                                                    "&js_code=" + URLEncoder.encode(code, StandardCharsets.UTF_8) +
                                                                    "&grant_type=authorization_code";
                                                            
                                                            return sendGetRequest(url);
                                                        } catch (Exception e) {
                                                            System.err.println("获取 session 失败: " + e.getMessage());
                                                            return null;
                                                        }
                                                    }

                                                /--
                                                * 刷新 access_token
                                                --/
                                                      public static JSONObject refreshAccessToken(String refreshToken) {
                                                          try {
                                                              String url = REFRESH_TOKEN_URL + "?" +
                                                                      "appid=" + URLEncoder.encode(APP_ID, StandardCharsets.UTF_8) +
                                                                      "&grant_type=refresh_token" +
                                                                      "&refresh_token=" + URLEncoder.encode(refreshToken, StandardCharsets.UTF_8);
                                                              
                                                              return sendGetRequest(url);
                                                          } catch (Exception e) {
                                                              System.err.println("刷新 access_token 失败: " + e.getMessage());
                                                              return null;
                                                          }
                                                      }

                                                /--
                                                * 获取用户信息
                                                --/
                                                      public static JSONObject getUserInfo(String accessToken, String openId) {
                                                          try {
                                                              String url = USER_INFO_URL + "?" +
                                                                      "access_token=" + URLEncoder.encode(accessToken, StandardCharsets.UTF_8) +
                                                                      "&open_id=" + URLEncoder.encode(openId, StandardCharsets.UTF_8);
                                                              
                                                              return sendGetRequest(url);
                                                          } catch (Exception e) {
                                                              System.err.println("获取用户信息失败: " + e.getMessage());
                                                              return null;
                                                          }
                                                      }

                                                /--
                                                * 发送 HTTP GET 请求
                                                --/
                                                    private static JSONObject sendGetRequest(String url) throws IOException {
                                                        URL obj = new URL(url);
                                                        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
                                                        
                                                        // 设置请求头和超时
                                                        con.setRequestMethod("GET");
                                                        con.setConnectTimeout(5000);
                                                        con.setReadTimeout(5000);
                                                        
                                                        // 获取响应
                                                        int responseCode = con.getResponseCode();
                                                        if (responseCode == HttpURLConnection.HTTP_OK) {
                                                            BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                    con.getInputStream(), StandardCharsets.UTF_8));
                                                            String inputLine;
                                                            StringBuilder response = new StringBuilder();
                                                            
                                                            while ((inputLine = in.readLine()) != null) {
                                                                response.append(inputLine);
                                                            }
                                                            in.close();
                                                            
                                                            return JSONObject.parseObject(response.toString());
                                                        } else {
                                                            System.err.println("HTTP 请求失败，状态码: " + responseCode);
                                                            return null;
                                                        }
                                                    }

                                                /--
                                                * 示例调用流程
                                                --/
                                                    public static void main(String[] args) {
                                                        // 1. 从前端获取 code（实际开发中由前端传递）
                                                            String code = "code_from_frontend";
                                                        
                                                        // 2. 使用 code 获取 session 信息
                                                            JSONObject sessionInfo = getSessionByCode(code);
                                                            if (sessionInfo == null || sessionInfo.containsKey("errcode")) {
                                                                System.err.println("获取 session 失败: " + sessionInfo);
                                                                return;
                                                            }
                                                        
                                                            String accessToken = sessionInfo.getString("access_token");
                                                            String openId = sessionInfo.getString("openid");
                                                            String refreshToken = sessionInfo.getString("refresh_token");
                                                            
                                                            System.out.println("获取 access_token 成功: " + accessToken);
                                                        
                                                        // 3. 使用 access_token 获取用户信息
                                                            JSONObject userInfo = getUserInfo(accessToken, openId);
                                                            if (userInfo != null && !userInfo.containsKey("errcode")) {
                                                                System.out.println("用户信息: " + userInfo.toJSONString());
                                                            } else {
                                                                System.err.println("获取用户信息失败: " + userInfo);
                                                                
                                                                // 4. 尝试刷新 access_token（假设原 token 已过期）
                                                                JSONObject refreshedToken = refreshAccessToken(refreshToken);
                                                                if (refreshedToken != null && !refreshedToken.containsKey("errcode")) {
                                                                    accessToken = refreshedToken.getString("access_token");
                                                                    System.out.println("刷新 access_token 成功: " + accessToken);
                                                                    
                                                                    // 5. 使用新的 access_token 再次尝试获取用户信息
                                                                    userInfo = getUserInfo(accessToken, openId);
                                                                    if (userInfo != null && !userInfo.containsKey("errcode")) {
                                                                        System.out.println("刷新后获取用户信息成功: " + userInfo.toJSONString());
                                                                    }
                                                                }
                                                            }
                                                    }
                                                }

                                <2>、应用及API调用示例（获取小程序配置）

                                                import java.io.BufferedReader;
                                                import java.io.IOException;
                                                import java.io.InputStreamReader;
                                                import java.net.HttpURLConnection;
                                                import java.net.URL;
                                                import java.net.URLEncoder;
                                                import java.nio.charset.StandardCharsets;
                                                import java.util.HashMap;
                                                import java.util.Map;
                                                import com.alibaba.fastjson.JSONObject;

                                                public class DouyinAppApi {
                                                    // 替换为你的应用凭证
                                                    private static final String APP_ID = "your_app_id";
                                                    private static final String APP_SECRET = "your_app_secret";
                                                    
                                                    // API 接口地址
                                                    private static final String APP_TOKEN_URL = "https://developer.toutiao.com/api/apps/token";
                                                    private static final String USER_INFO_URL = "https://developer.toutiao.com/api/user/info";
                                                    
                                                    // 缓存应用级 access_token
                                                    private static String appAccessToken;
                                                    private static long tokenExpireTime = 0;

                                                    /--
                                                    * 获取应用级 access_token（自动缓存并刷新）
                                                    --/
                                                    public static String getAppAccessToken() throws IOException {
                                                        // 检查缓存的 token 是否有效（提前 5 分钟刷新）
                                                            if (appAccessToken != null && System.currentTimeMillis() < tokenExpireTime - 5 * 60 * 1000) {
                                                                return appAccessToken;
                                                            }
                                                        
                                                        // 构建请求 URL
                                                            String url = APP_TOKEN_URL + "?" +
                                                                    "appid=" + URLEncoder.encode(APP_ID, StandardCharsets.UTF_8) +
                                                                    "&secret=" + URLEncoder.encode(APP_SECRET, StandardCharsets.UTF_8) +
                                                                    "&grant_type=client_credential";
                                                        
                                                        // 发送请求
                                                            JSONObject response = sendGetRequest(url);
                                                            if (response == null || response.containsKey("errcode")) {
                                                                throw new IOException("获取应用级 access_token 失败: " + response);
                                                            }
                                                        
                                                        // 缓存 token 和过期时间
                                                            appAccessToken = response.getString("access_token");
                                                            int expiresIn = response.getIntValue("expires_in");
                                                            tokenExpireTime = System.currentTimeMillis() + expiresIn * 1000;
                                                            
                                                            return appAccessToken;
                                                    }

                                                    /--
                                                    * 获取用户信息（应用级 API）
                                                    --/
                                                    public static JSONObject getUserInfo(String openId) throws IOException {
                                                        // 获取应用级 access_token
                                                            String accessToken = getAppAccessToken();
                                                        
                                                        // 构建请求 URL
                                                            String url = USER_INFO_URL + "?" +
                                                                    "access_token=" + URLEncoder.encode(accessToken, StandardCharsets.UTF_8) +
                                                                    "&open_id=" + URLEncoder.encode(openId, StandardCharsets.UTF_8);
                                                        
                                                        // 发送请求
                                                            return sendGetRequest(url);
                                                    }

                                                    /--
                                                    * 发送 HTTP GET 请求
                                                    --/
                                                    private static JSONObject sendGetRequest(String url) throws IOException {
                                                        URL obj = new URL(url);
                                                        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
                                                        
                                                        // 设置请求头和超时
                                                            con.setRequestMethod("GET");
                                                            con.setConnectTimeout(5000);
                                                            con.setReadTimeout(5000);
                                                        
                                                        // 获取响应
                                                            int responseCode = con.getResponseCode();
                                                            if (responseCode == HttpURLConnection.HTTP_OK) {
                                                                BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                        con.getInputStream(), StandardCharsets.UTF_8));
                                                                String inputLine;
                                                                StringBuilder response = new StringBuilder();
                                                                
                                                                while ((inputLine = in.readLine()) != null) {
                                                                    response.append(inputLine);
                                                                }
                                                                in.close();
                                                                
                                                                return JSONObject.parseObject(response.toString());
                                                            } else {
                                                                // 读取错误信息
                                                                BufferedReader errorReader = new BufferedReader(new InputStreamReader(
                                                                        con.getErrorStream(), StandardCharsets.UTF_8));
                                                                String errorLine;
                                                                StringBuilder errorResponse = new StringBuilder();
                                                                
                                                                while ((errorLine = errorReader.readLine()) != null) {
                                                                    errorResponse.append(errorLine);
                                                                }
                                                                errorReader.close();
                                                                
                                                                throw new IOException("HTTP 请求失败，状态码: " + responseCode +
                                                                        ", 错误信息: " + errorResponse.toString());
                                                            }
                                                    }

                                                    /--
                                                    * 示例调用流程
                                                    --/
                                                    public static void main(String[] args) {
                                                        try {
                                                            // 用户的 open_id（从数据库或其他途径获取）
                                                                String openId = "user_open_id";
                                                            
                                                            // 获取用户信息
                                                                JSONObject userInfo = getUserInfo(openId);
                                                                
                                                                if (userInfo != null && !userInfo.containsKey("errcode")) {
                                                                    System.out.println("用户信息获取成功:");
                                                                    System.out.println("昵称: " + userInfo.getString("nickname"));
                                                                    System.out.println("头像: " + userInfo.getString("avatar"));
                                                                    // 其他字段...
                                                                } else {
                                                                    System.err.println("获取用户信息失败: " + userInfo);
                                                                }
                                                        } catch (IOException e) {
                                                            System.err.println("调用 API 异常: " + e.getMessage());
                                                        }
                                                    }
                                                }
          */

</script>